Skip to content

fix(chat): strip runtime turn context from projection before model input#560

Closed
sentry-junior[bot] wants to merge 2 commits into
mainfrom
fix/strip-projection-runtime-context
Closed

fix(chat): strip runtime turn context from projection before model input#560
sentry-junior[bot] wants to merge 2 commits into
mainfrom
fix/strip-projection-runtime-context

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Problem

When a follow-up message arrives in an existing Slack thread started by a different user, the requester attribution for model-generated content (such as the Action taken on behalf of line in PR bodies) would be wrong — showing the original thread starter instead of the person who actually made the request.

Root Cause

The session log projection stores pi_message entries as-is, including any runtime turn context blocks (<runtime-turn-context>...<requester>...</requester>...) that were embedded in user messages from prior turns.

In loadPiMessagesForTurn, the active-turn resume path correctly strips old runtime context before returning:

return {
  piMessages: stripRuntimeTurnContext(
    trimTrailingAssistantMessages(sessionRecord.piMessages),
  ),
};

But the projection path did not strip:

return {
  canCompact: true,
  piMessages: projection,   // ← no strip — bug
};

When hasRuntimeTurnContext(priorPiMessages) found the old context from user A's session, it returned true, so needsBootstrapContext = false and user B's identity was never injected into the prompt. The model then used user A's stale <requester> block for any attributions it generated.

Note: git commit co-author attribution was unaffected — that path uses the per-turn resolved identity directly rather than the model prompt.

Fix

Apply stripRuntimeTurnContext to the projection path, making it consistent with the active-turn resume path:

return {
  canCompact: true,
  piMessages: stripRuntimeTurnContext(projection),
};

Context compaction already calls stripRuntimeTurnContext internally, so no double-strip concern.

Verification

  • tsc --noEmit clean
  • New regression test: projection with user A's embedded requester context does not suppress injection of user B's requester context after stripping
  • 3 tests pass (respond-helpers-runtime-context.test.ts)

Remaining Risk

Other consumers of loadProjection that check hasRuntimeTurnContext on the result could have the same class of bug, though the main model-input path flows through loadPiMessagesForTurn. Compaction is already safe (strips internally).

When a follow-up message arrives in an existing Slack thread, the
session log projection may contain runtime turn context blocks that were
written by prior turns (e.g. from the original thread starter). These
blocks carry the earlier requester's identity.

`loadPiMessagesForTurn` checked `hasRuntimeTurnContext` against the raw
projection. If it returned true, the current turn's context (including
the actual requester for this message) was never injected into the
prompt. The model then used the stale requester identity for attributions
such as the `Action taken on behalf of` line in PR bodies.

The active-turn resume path already calls `stripRuntimeTurnContext`
before returning piMessages. Apply the same strip to the projection path
so both paths are consistent and fresh requester context is always
injected for the current turn.

Adds a regression test covering the multi-user thread scenario where the
projection carries a stale requester block from user A, and user B's
follow-up must inject fresh requester context.

Refs: https://sentry.slack.com/archives/C0AHB7N2JCR/p1780911303272149

Co-authored-by: no <nelson.osacky@sentry.io>
@vercel

vercel Bot commented Jun 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
junior-docs Ready Ready Preview, Comment Jun 8, 2026 12:42pm

Request Review

@dcramer

dcramer commented Jun 8, 2026

Copy link
Copy Markdown
Member

Will dig into this. We likely need to maintain some identity block per message

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant